#define MSNETWORK_C
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/tcp.h>
#if defined(OS_ANDROID)||defined(OS_LINUX_SOC)
#include <strings.h>
#include <sys/select.h>
#endif
#if defined(OS_WIN32)
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#if defined(OS_LINUX_SOC)
#include <netdb.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <libmslog/mslog.h>
#include "msmd.h"
#include "mscommon.h"
#include "msnetwork.h"
#include "msstring.h"
#include "msepoll.h"
#include "mstime.h"

#define FLAG "NETWORK"
ms_s08 msnet_api_init(ms_void)
{
#if defined(OS_WIN32)
	WSADATA wsaData;
	if( WSAStartup(MAKEWORD(2,2), &wsaData) !=0 ){
		return -1;
	}
	//ms_debug( "SockwVersion:%d.%d",LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
	if (LOBYTE(wsaData.wVersion)!=2 || HIBYTE(wsaData.wVersion)!=2	){
		WSACleanup();
		return -1;
	}	
#endif
	return 0;
}

ms_void msnet_api_deinit(ms_void)
{
#if defined(OS_WIN32)
	WSACleanup();
#endif
}
/*服务（IP+PORR）是否可连接，用于线路是否可连通的判断*/
ms_bool msnet_api_isReachable(ms_string ms_in paddr,ms_s32 port)	//"www.baidu.com"
{  
#if defined(OS_LINUX_SOC)
	ms_bufcheckRetDes(ms_false, paddr,"Param error####pingaddr");
	struct hostent* host = gethostbyname(paddr);  
	if(ms_null == host)  {  
		return ms_false;
	}  
	int  sock_cli = socket(AF_INET,SOCK_STREAM, 0);  
	struct sockaddr_in servaddr;  
	memset(&servaddr, 0, sizeof(servaddr));  
	servaddr.sin_family = AF_INET;  
	if(-1==port){	servaddr.sin_port = htons(80);  
	}else{		servaddr.sin_port = htons(port);  }
	servaddr.sin_addr = *((struct in_addr *)host->h_addr);  
	if (msnet_api_socketConnect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr),1000000,ms_false)< 0){
		ms_close(sock_cli);
		return ms_false;
	}	
	ms_close(sock_cli);
	return ms_true;  
#else
	ms_funcNosupports;
	return ms_false;
#endif
}  
ms_s32 msnet_api_socketNonblock(ms_s32 ms_io socket, ms_bool ms_in enable)
{
#if defined(OS_ANDROID)||defined(OS_LINUX_SOC)
	if (ms_true==enable){
		return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK);
	}else{
		return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK);
	}
#endif
}
ms_s08 msnet_api_socketConnect(ms_s32 ms_io  socket, struct sockaddr * ms_in plisten_addr,
	ms_u32 ms_in len,ms_u64 ms_in timeout,ms_bool flag_pint)
{
	if(timeout>0){
		if (msnet_api_socketNonblock(socket, 1) < 0){
			ms_errRet(-1, "msnet_api_socketNonblock %d failed",socket);
		}else{
			//ms_debug("msnet_api_socketNonblock %d sucess",socket);
		}
	}
	ms_s08 ret=-1;
	ms_u64 noin_basetime=mstime_api_us();
	struct tcp_info info; 
	char outstr[128]={0};
	ms_u32 infolen=sizeof(info); 	
	ms_u32 num=0;
	ms_s32 msepoll_fd=msepoll_open(2);
	
	ms_u64 sleeptime=(timeout/10);
	//避免休眠时间过长，导致连接耗时太长，从而引发的异常问题
	if(sleeptime>ms_usmseconds(10)){
		sleeptime=ms_usmseconds(10);
	}
	while ((ret = connect(socket, plisten_addr,len))) {
		//ms_debug( "connect faild(%d),(errno:%d,%s)", socket,errno,strerror(errno));
		num+=1;
		if((mstime_api_us()-noin_basetime)>timeout){
			ret=-1;
			goto msend;
		}
#if 1		
		char str_tcpi_state[128]={0};
		if(ms_false==msnet_api_isTcpStateOK(socket,ms_null ,str_tcpi_state) ){
		#if 0
			ms_waring("tryconnect num(%d),socketconnect failed:%s",num,str_tcpi_state);
		#endif
		}else{
			ret=0;
			break;
		}
#endif	
		ms_usleep(sleeptime);
	}
	ms_u64 noin_casttime=(mstime_api_us()-noin_basetime);
	ms_verbose("connect sucess,timecast:%s us",ms_num2str(noin_casttime));
	msepoll_close(&msepoll_fd);
	return ret;
msend:	
	if(ms_true==flag_pint){
		ms_waring("tryconnect num(%d),socketconnect failed,tcpi_state:%d-%s,timeout:%s",num,info.tcpi_state,outstr,ms_num2str(timeout));
	}
	msepoll_close(&msepoll_fd);
	return ret;
}
ms_s32 msnet_api_poll(struct pollfd * ms_in fds, nfds_t ms_in numfds, ms_u32 ms_in timeout)
{
	fd_set read_set;
	fd_set write_set;
	fd_set exception_set;
	FD_ZERO(&read_set);
	FD_ZERO(&write_set);
	FD_ZERO(&exception_set);
	
	ms_s32 n = 0;
	nfds_t i;
	for (i = 0; i < numfds; i++) {
		if (fds[i].fd < 0){
			continue;
		}
		if (fds[i].events & POLLIN){
			FD_SET(fds[i].fd, &read_set);
		}
		if (fds[i].events & POLLOUT){
			FD_SET(fds[i].fd, &write_set);
		}
		if (fds[i].events & POLLERR){
			FD_SET(fds[i].fd, &exception_set);
		}
		if (fds[i].fd >= n){
			n = fds[i].fd + 1;
		}
	}

	if (n == 0){
		/* Hey!? Nothing to poll, in fact!!! */
		return 0;
	}
	ms_s32 rc;
	if (timeout < 0) {
		rc = select(n, &read_set, &write_set, &exception_set, NULL);
	} else {
		struct timeval tv;
		tv.tv_sec  = timeout / 1000;
		tv.tv_usec = 1000 * (timeout % 1000);
		rc= select(n, &read_set, &write_set, &exception_set, &tv);
	}

	if (rc < 0){
		return rc;
	}

	for (i = 0; i < numfds; i++) {
		fds[i].revents = 0;
		if (FD_ISSET(fds[i].fd, &read_set)){
			fds[i].revents |= POLLIN;
		}
		if (FD_ISSET(fds[i].fd, &write_set)){
			fds[i].revents |= POLLOUT;
		}
		if (FD_ISSET(fds[i].fd, &exception_set)){
			fds[i].revents |= POLLERR;
		}
	}
	return rc;
}
ms_s32 msnet_api_waitFd(ms_s32 ms_in fd, ms_bool ms_in is_write)
{
	#define RETRY_MAX 10	//100*10=1S,low level READ.
	
	ms_s32 ev = (ms_true==is_write) ? POLLOUT : POLLIN;
	struct pollfd p = { .fd = fd, .events = ev, .revents = 0 };
	ms_s32 ret=0;
	ms_s32 retry=RETRY_MAX; 
	do{
		ret = msnet_api_poll(&p, 1, 100);/*100ms*/
		if(ret!=0){
			break;/*fd ready or errors*/
		}
		if(retry<RETRY_MAX-5 ){ /*at lest try 5 times, for some teardown command*/
			return -1;
		}
	}while(retry-->0);
	return ret ;
}

ms_s32 msnet_api_waitFdTimeout(ms_s32 ms_in fd, ms_s32 ms_in is_write,ms_s32 ms_in retrytime)
{
	ms_s32 ev = (ms_true==is_write) ? POLLOUT : POLLIN;
	struct pollfd p = { .fd = fd, .events = ev, .revents = 0 };
	ms_s32 ret=0;
	do{
		ret = poll(&p, 1, 100);/*100ms*/
		if(ret!=0)
			break;/*fd ready or errors*/
	}while(retrytime-->0);

	if(!(retrytime>0)){
		ret=-1;
	}
	return ret ;
}
ms_bool msnet_api_isIpv6(ms_string ms_in ipaddr)
{
	if(msstr_api_isCasestr(ipaddr, ":")){
		return ms_true;
	}else{
		return ms_false;
	}
}
ms_bool msnet_api_isMulticast( ms_string ms_in paddr)
{
#ifndef IN_MULTICAST
#define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
#endif
#ifndef IN6_IS_ADDR_MULTICAST
#define IN6_IS_ADDR_MULTICAST(a) (((ms_pu08 ) (a))[0] == 0xff)
#endif
	if(ms_false==msnet_api_isIpv6( paddr)){
		return IN_MULTICAST(ntohl( inet_addr(paddr))) ? ms_true : ms_false;
	}else{
		struct sockaddr_in6 paddr6;
		inet_pton(AF_INET6,paddr,&paddr6.sin6_addr);
		return IN6_IS_ADDR_MULTICAST(&paddr6.sin6_addr)? ms_true : ms_false;
	}
}
ms_void msnet_api_getIpaddr(struct sockaddr *addr,ms_byte *ipaddrbuf)
{
	if (addr->sa_family == AF_INET6) {
		inet_ntop(AF_INET6,&(((struct sockaddr_in6 *)addr)->sin6_addr),ipaddrbuf, 128);
		
		if(ms_strncmp_seq(ipaddrbuf, "::ffff:")){
			ms_bufOffset(ipaddrbuf, ms_buflen("::ffff:"), (ms_buflen(ipaddrbuf)-ms_buflen("::ffff:")));
			ms_verbose("---ipv6,ipv4:::ffff:%s,%s",ipaddrbuf,ipaddrbuf);
		}else{
			ms_verbose("---ipv6:%s",ipaddrbuf);
		}
	}else{
		//inet_ntoa(((struct sockaddr_in *)addr)->sin_addr);
		//ms_verbose("---ipv4:%s",ipaddrbuf);
		inet_ntop(AF_INET,&(((struct sockaddr_in *)addr)->sin_addr),ipaddrbuf,  128);
		ms_verbose("---ipv4:%s",ipaddrbuf);
	}
}
ms_bool msnet_api_isResIpaddr( ms_string ms_in pipaddr)
{
	if(ms_true==msnet_api_isIpv6( pipaddr)){
		ms_dbgRet(ms_false, "no support  ipv6");
	}
//aliyun 100.64.0.0/10		255.192.0.0
	ms_byte ipaddr[256]={0};
	ms_strcpy(ipaddr, pipaddr);
	
	ms_string str_ipaddr_item[256];
	ms_u08  ipaddr_item[4]={0};
	ms_u08 ipaddr_num=msstr_api_split2(ipaddr, ".", str_ipaddr_item);	
	if(4!=ipaddr_num){
		ms_errRet(ms_false, "Error ipaddr(%s),num is %d",pipaddr,ipaddr_num)
	}
	ms_u32 ipaddr_1=ms_atoi(str_ipaddr_item[0]);
	ms_u32 ipaddr_2=ms_atoi(str_ipaddr_item[1]);
	return ( (100==(ipaddr_1 & 255))&&(64==(ipaddr_2 & 192))	) ? ms_true : ms_false;
}
/*域名解析*/
ms_s08 msnet_api_parseDomainName (ms_string ms_in phostname, ms_string ms_in pservice,MSIPlist *pmsiplist)
{
#if defined(OS_LINUX_SOC)
	ms_bufcheckRetDes(-1, phostname,"Param error####hostname");
	ms_pamNocheck(pservice);
	ms_bufcheckRetDes(-1, pmsiplist,"Param error####ipaddr");
	if(0==ms_buflen(phostname)){
		ms_errRet(-1,"phostname %s len is 0,ret -1",phostname);
	}
	ms_memset(pmsiplist,0,sizeof(MSIPlist));

	struct addrinfo *result, hints, *curr;
	bzero(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	if (0 != getaddrinfo(phostname, pservice, &hints, &result)) {
		ms_errRet(-1,"getaddrinfo %s failed",phostname);
	}
	if(NULL==result){
		ms_errRet(-2,"No addrinfo");
	}

	for (curr = result; curr != NULL; curr = curr->ai_next) {
		if (curr->ai_family == AF_INET6){
			inet_ntop(AF_INET6,&(((struct sockaddr_in6 *)(curr->ai_addr))->sin6_addr),pmsiplist->ipaddr[pmsiplist->totalnum], 128);
			pmsiplist->flag_ipv6[pmsiplist->totalnum]=ms_true;
		}else{
			inet_ntop(AF_INET,&(((struct sockaddr_in *)(curr->ai_addr))->sin_addr),pmsiplist->ipaddr[pmsiplist->totalnum], 128);
			pmsiplist->flag_ipv6[pmsiplist->totalnum]=ms_false;
		}
		ms_verbose("phostname:%s--%d:%s", phostname,pmsiplist->totalnum,pmsiplist->ipaddr[pmsiplist->totalnum]);
		pmsiplist->totalnum++;
	}
	freeaddrinfo(result);
	return 0;
#else
	ms_funcNosupports;
	return 0;
#endif
}
ms_void msnet_api_outIpv6(ms_pbyte ms_in ipaddr)
{
	if(ms_false==msnet_api_isIpv6(ipaddr)){
		ms_byte ipaddr_ipv6[256]={0};
		ms_sprintfs(ipaddr_ipv6, "::ffff:%s",ipaddr);
		ms_strcpy(ipaddr,ipaddr_ipv6);
	}
}
ms_s08 msnet_api_getIfaceInfo(NETCFGInfo * ms_out pnetcfg_info)  
{  
	ms_s08 ret=0;
	ms_bufcheckRetDes(-1, pnetcfg_info,"Param error####pnetcfg_info");
	//create socket
	ms_s32 fd = socket(AF_INET, SOCK_DGRAM, 0);    
	if(fd <0){
		ret=-1;
		ms_errGoto(ms_end, "Create socket falied");
	}
	//Set ifacename
	struct ifreq ifr;
	bzero( &ifr,sizeof(ifr)); 
	strncpy(ifr.ifr_name, pnetcfg_info->name, IFNAMSIZ);
	ifr.ifr_name[IFNAMSIZ - 1] = 0;
	//Get ipaddress
	if (!(ioctl(fd, SIOCGIFADDR, &ifr) < 0) ){
		struct in_addr if_ip;
		if_ip.s_addr  = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
		ms_strcpy(pnetcfg_info->ipaddress,inet_ntoa(if_ip));
	}else{
		ms_memset(pnetcfg_info->ipaddress, 0, ms_bufsize(pnetcfg_info->ipaddress));
	}
	//Get netmask
	if( !((ioctl( fd, SIOCGIFNETMASK, &ifr ) ) < 0 ))   {  
		struct sockaddr_in *net_mask = ( struct sockaddr_in * )&( ifr.ifr_netmask );  
		strcpy( pnetcfg_info->netmask, inet_ntoa( net_mask -> sin_addr ) );  
	}else{
		ms_memset(pnetcfg_info->netmask, 0, ms_bufsize(pnetcfg_info->netmask));
	}  
ms_end:
	ms_close(fd);
	return ret;
}  
ms_s08 msnet_api_setIfaceInfo(NETCFGInfo *  ms_in pnetcfg_info)  
{  
	ms_bufcheckRetDes(-1, pnetcfg_info, "Param error####pnetcfg_info");
	//create socket
	ms_s32 fd = socket( AF_INET, SOCK_DGRAM, 0 )  ;  
	if(fd <0){
		ms_errGoto(ms_failed, "Create socket falied");
	}
	//set ifacename
	struct ifreq ifr;
	bzero( &ifr,sizeof(ifr)); 
	strncpy(ifr.ifr_name, pnetcfg_info->name, IFNAMSIZ);
	ifr.ifr_name[IFNAMSIZ - 1] = 0;
	//set ipaddress
	struct sockaddr_in sin_set_ip;  
	ms_memset( &sin_set_ip, 0, sizeof(sin_set_ip));  
	sin_set_ip.sin_family = AF_INET;  
	sin_set_ip.sin_addr.s_addr = inet_addr(pnetcfg_info->ipaddress);  
	memcpy( &ifr.ifr_addr, &sin_set_ip, sizeof(sin_set_ip));  
	if( ioctl( fd, SIOCSIFADDR, &ifr) < 0 ) {  
		ms_errGoto(ms_failed, "SIOCSIFADDR  failed");  
	}  
	ifr.ifr_flags |= IFF_UP |IFF_RUNNING;  
	if( ioctl( fd, SIOCSIFFLAGS, &ifr ) < 0 )  {  
		ms_errGoto(ms_failed, "SIOCSIFFLAGS  failed");  
	} 
	//set netmask
	ms_u08  netmask_addr[32];     
	struct sockaddr_in *sin_net_mask = (struct sockaddr_in *)&ifr.ifr_addr;  
	sin_net_mask -> sin_family = AF_INET;  
	inet_pton(AF_INET, pnetcfg_info->netmask, &sin_net_mask ->sin_addr);  
	if(ioctl(fd, SIOCSIFNETMASK, &ifr ) < 0){  
		ms_errRet(-1, "SIOCSIFNETMASK  failed");  
	}  
	ms_close(fd);
	return 0;
ms_failed:
	ms_close(fd);
	return -1;
}  

ms_s08 msnet_api_getIfaceIp(const ms_string ms_in pifname, ms_string ms_out pipaddr)
{
	ms_bufcheckRetDes(-1, pifname,"Param error####pifname");
	ms_bufcheckRetDes(-1, pipaddr,"Param error####pipaddr");
	struct in_addr if_ip;
	ms_string pscifip=NULL;
	struct ifreq ifr;
	//create socket
	ms_s32 fd = socket(AF_INET, SOCK_DGRAM, 0);    
	if(fd <0){
		ms_close(fd);
		ms_errRet(-1, "Create socket falied");
	}
	//Set ifacename
	memset(&ifr, 0, sizeof(struct ifreq));
	strncpy(ifr.ifr_name, pifname, IFNAMSIZ);
	ifr.ifr_name[IFNAMSIZ - 1] = 0;
	//Get ipaddress
	ms_s08 ret=0;
	if(ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
		if_ip.s_addr = 0;
		ret=-1;
	} else {
		if_ip.s_addr  = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
	}
	pscifip=inet_ntoa(if_ip);
	ms_strcpy(pipaddr,pscifip);
	close(fd);
	return ret;
}
ms_s08 msnet_api_getIfaceIpMask(const ms_string ms_in pifname, ms_string ms_out pipaddr, ms_string ms_out pnetmask)
{  
	ms_bufcheckRetDes(-1, pifname,"Param error####pifname");
	ms_bufcheckRetDes(-1, pipaddr,"Param error####pipaddr");
	ms_bufcheckRetDes(-1, pnetmask,"Param error####pnetmask");
	struct in_addr if_ip;
	ms_string pscifip=NULL;
	struct ifreq ifr;
	//create socket
	ms_s32 fd = socket(AF_INET, SOCK_DGRAM, 0);    
	if(fd <0){
		ms_close(fd);
		ms_errRet(-1, "Create socket falied");
	}
	//Set ifacename
	memset(&ifr, 0, sizeof(struct ifreq));
	strncpy(ifr.ifr_name, pifname, IFNAMSIZ);
	ifr.ifr_name[IFNAMSIZ - 1] = 0;
	//Get ipaddress
	ms_s08 ret=0;
	if(ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
		if_ip.s_addr = 0;
		ret=-2;
	} else {
		if_ip.s_addr  = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
		pscifip=inet_ntoa(if_ip);
		ms_strcpy(pipaddr,pscifip);
		if( (ioctl( fd, SIOCGIFNETMASK, &ifr ) ) < 0 )   {  
			struct sockaddr_in *net_mask = ( struct sockaddr_in * )&( ifr.ifr_netmask );  
			strcpy( pnetmask, inet_ntoa( net_mask -> sin_addr ) );  
		} 
	}
	ms_close( fd );  
	return  ret;
}
ms_s08 msnet_api_getIfaceMac_string(ms_string ms_in pifname,ms_string ms_out pmacstr,ms_u32 ms_in size)  
{
	ms_bufcheckRetDes(-1, pifname,"Param error####pifname");
	ms_bufcheckRetDes(-1, pmacstr,"Param error####pmacstr");
	if(size<msnet_maxlen_mac){
		ms_errRet(-2, "Mac bufsize(%d) must be lagre than 18", size);
	}
	ms_s08 sys_net_addr[128]={0};
	ms_sprintf(sys_net_addr,"/sys/class/net/%s/address",pifname);
	ms_s32 len=msmd_api_read(sys_net_addr,pmacstr,size);
	pmacstr[msnet_maxlen_mac-1]=0;
	return 0;
}
ms_s08 msnet_api_getIfaceMac_byte(ms_string ms_in pifname, ms_pbyte ms_out pmac)
{
	int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
	struct ifreq s;
	ms_strcpy(s.ifr_name, pifname);
	int ret = ioctl(fd, SIOCGIFHWADDR, &s);
	close(fd);
	if (ret != 0){
		ms_errRet(-1, "ioctl SIOCGIFHWADDR failed");
	}
	ms_memcpy((void *)pmac, s.ifr_addr.sa_data, 6);
	return 0;
}
ms_s08 msnet_api_getIfaceMtu(ms_string ms_in pifname,ms_string ms_in mtubuf,ms_u32 ms_in size)  
{
	if(size<msnet_maxlen_mtu){
		ms_errRet(-2, "MTU bufsize(%d) must be lagre than 16", size);
	}
	ms_u08 sys_net_addr[128]={0};
	ms_sprintfs(sys_net_addr,"/sys/class/net/%s/mtu",pifname);
	ms_s32 len=msmd_api_read(sys_net_addr,mtubuf,size);
	if(len<0){
		ms_errRet(-1,"Write mtu val failed");
	}	
	if(len<size){
		mtubuf[len]=0;
	}
	return 0;
}
ms_s08 msnet_api_setIfaceMtu(ms_string ms_in pifname,ms_u32 ms_in mtuval)  
{
	ms_u08 sys_net_addr[128]={0};
	ms_u08 mtubuf[msnet_maxlen_mtu]={0};
	ms_sprintfs(sys_net_addr,"/sys/class/net/%s/mtu",pifname);
	ms_sprintfs(mtubuf,"%d",mtuval);
	if(msmd_api_write(sys_net_addr,mtubuf,ms_buflen(mtubuf),"w")<0){
		ms_errRet(-1,"Write mtu val failed");
	}	
}

ms_s08 msnet_api_setIfaceFlags( ms_s32 ms_in fd  ,ms_string ms_in pifname, ms_u32 ms_in flags) 
{ 
	ms_bufcheckRetDes(-1, pifname, "Param error####pifname");
	struct ifreq ifr;
	strncpy(ifr.ifr_name, pifname ,strlen( pifname )+1); 
	if((ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)) {          
		ms_errRet(-1,"ioctl(SIOCGIFFLAGS) failed"); 
	} 
	ifr.ifr_flags |= flags;                  
	if(ioctl(fd, SIOCSIFFLAGS, &ifr) == -1 ) {        
		ms_errRet(-1,"ioctl(SIOCSIFFLAGS) failed"); 
	}
	return 0;
} 

ms_void msnet_api_macByte2str(ms_pbyte pbuf,ms_u32 len,ms_pbyte pstrout)
{
	ms_u32 index=0;
	ms_u08 tbuf[16]={0};
	for(index=0;index<len;index++){
		ms_strcats(tbuf, pstrout, "%x", pbuf[index]);
		if((index+1)<len){
			ms_strcats(tbuf, pstrout, ":");
		}
	}
}
//chage mac-string to mac-bin 
ms_s08 msnet_api_macStr2Byte( ms_string ms_in pmacstr, ms_string ms_out poutbuf)
{
	ms_bufcheckRetDes(-1, pmacstr, "Param error####pmacstr");
	ms_bufcheckRetDes(-1, poutbuf, "Param error####poutbuf");
	int i;
	ms_ps08 e;
	ms_ps08 s = (ms_ps08) pmacstr;
	for (i = 0; i < 6; ++i){
		poutbuf[i] = s ? strtoul (s, (char **)&e, 16) : 0;
		if (s){
			s = (*e) ? e + 1 : e;
		}
	}
	return 0;
}
ms_bool msnet_api_isVaildMac( ms_string ms_in pmacstr)
{
	ms_bufcheckRetDes(-1, pmacstr, "Param error####pmacstr");
	int i;
	ms_ps08 e;
	ms_ps08 s = (ms_ps08) pmacstr;
	ms_byte outbuf[6]={0};
	for (i = 0; i < 6; ++i){
		outbuf[i] = s ? strtoul (s, (char **)&e, 16) : 0;
		if (s){
			s = (*e) ? e + 1 : e;
		}
	}
	return (0==(outbuf[0]%2)) ? ms_true : ms_false;
}
/*当发送目的IP为组播时，获取目的MAC*/
ms_void msnet_api_getMulticastDestMac(ms_string destMac,ms_string pmaddr)
{
	ms_u32 maddr=htonl(inet_addr(pmaddr));
	ms_byte ipaddr_buf[256]={0};
	ms_network_4b(ipaddr_buf, maddr);
	ms_sprintfs(destMac, "01:00:5e:%02x:%02x:%02x", ipaddr_buf[1],ipaddr_buf[2],ipaddr_buf[3]);
}
ms_u32 msnet_api_ipStr2Byte( ms_string ms_in pipstr)
{
	ms_byte pipaddr_tmp[16]={0};
	ms_strcpy(pipaddr_tmp, pipstr);
	ms_string str_ipaddr_item[256];
	ms_u08 ipaddr_num=msstr_api_split(pipaddr_tmp, ".", str_ipaddr_item);	
	if(4!=ipaddr_num){
		ms_errRet(ms_false, "Error pipaddr_start(%s),num is %d",pipaddr_tmp,ipaddr_num)
	}
	ms_u08  ipaddr_item[4]={0};
	ms_u32 index=0;
	for(index=0;index<4;index++){
		ipaddr_item[index]	=ms_atoi(str_ipaddr_item[index]);
	}
	ms_u32 ipaddr_totalnum=ms_host_4b(ipaddr_item);
	return ipaddr_totalnum;
}

ms_void msnet_api_ipByte2Str( ms_u32 ms_in ipaddr_num, ms_string ms_out poutbuf)
{
	ms_u08  ipaddr_item[4]={0};
	ms_network_4b(ipaddr_item, ipaddr_num);
	ms_sprintfs(poutbuf, "%d.%d.%d.%d", ipaddr_item[0], ipaddr_item[1], ipaddr_item[2], ipaddr_item[3]);
}
ms_u16 msnet_api_checksum(ms_pu16 ms_in paddr,ms_u32 ms_in bytes)
{
	ms_bufcheckRetDes(ms_f16, paddr, "Param error####paddr");
	ms_u32 sum=0;
	while(bytes>1){
		sum+=*paddr++;
		bytes-=2;
	 }
	if(bytes==1){
		sum+=*(ms_pbyte)paddr;
	}
	sum=((sum&0xffff0000)>>16)+(sum&0xffff);  
	sum+=((sum&0xffff0000)>>16);   
	sum=(~sum);
	sum=((sum&0xff00)>>8|(sum&0xff)<<8);
	return sum;
}

ms_u16 msnet_api_checksumUdp(ms_pu16 ms_in paddr,ms_u32 ms_in bytes)
{
	unsigned long sum;
	for(sum=0;bytes>0;bytes-=2){
		sum += *paddr++;
		sum = (sum>>16) + (sum&0xffff);
	}
	return ~sum;
}

//udp,tcp and so on
ms_u16 msnet_api_checksum_ptc(ms_pbyte ms_in  pether_pkt,
	ms_u32  source_ip,ms_u32  dest_ip,
	ms_u08  protocol,
	ms_u08  header_len,ms_pbyte data,ms_u16 data_len)	
{
	ms_bufcheckRetDes(ms_f16,pether_pkt,"Param error####pether_pkt");
	ms_byte check_buf[2048]={0};
	/*----extern  header----*/
	//source_ip
	ms_network_4b(&(check_buf[0]), source_ip);
	//dest_ip
	ms_network_4b(&(check_buf[4]), dest_ip);
	//0
	check_buf[8]=0;
	//protocol
	check_buf[9]=protocol;
	//len
	ms_network_2b(&(check_buf[10]), (header_len+data_len));
	
	/*header*/
	ms_memcpy(&check_buf[12], pether_pkt, header_len);
	/*data*/
	ms_memcpy(&check_buf[12+header_len], data, data_len);
	return msnet_api_checksum((ms_u16 * )check_buf, 12+header_len+data_len);	
}

ms_void msnet_api_getTcpStateString( MSNETTCPState ms_in msnet_tcpstate,ms_string ms_out outstr) 
{ 
	static ms_string pnetsate_string[128]={
		"?:unkonw",
		"1-established:all is ok(client-state,server-state )",
		"2-syn_send:syn is send(client-state when send connect request)",
		"3-syn_recv:syn is received(server-state when received connect request)",
		"4-fin_wait1:fin is first-send(client-state,server-state when  first-sendfin pkt)",
		"5-fin_wait2:fin is first-acked(client-state,server-state when first-recv fin-ack pkt)",
		"6-time_wait",
		"7-close",
		"8-close_wait",
		"9-last_ack",
		"10-listen",
		"11-closing",
	};
	if(ms_range(msnet_tcpstate, msnet_tcp_established, msnet_tcp_closing)){
		ms_strcpy(outstr, pnetsate_string[msnet_tcpstate]);
	}else{
		ms_strcpy(outstr, pnetsate_string[msnet_tcp_unkonw]);
	}
} 
/*网卡绑定*/
ms_s08 msnet_api_bindIface(ms_s32 ms_in fd , ms_string ms_in pifname) 
{ 
	ms_bufcheckRetDes(-1, pifname, "Param error####pifname");
	if(ms_buflen(pifname)>0){
		ms_verbose("--------------pifname----%s", pifname);
		struct ifreq ifr;
		ms_memset(&ifr, 0,sizeof(struct ifreq));
		strncpy(ifr.ifr_name, pifname, IFNAMSIZ);
		if(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (ms_ps08)&ifr, sizeof(ifr)) ){
			ms_errRet(-1,"setsockopt(SO_BINDTODEVICE) (%d,%s)", errno, strerror(errno));
		}				
		ms_s32 dontroute = 0;
		if (setsockopt(fd,SOL_SOCKET, SO_DONTROUTE,&dontroute, sizeof(dontroute)) < 0) {
			ms_errRet(-1, "setsockopt(SO_DONTROUTE)(%d,%s)", errno, strerror(errno));
		}
	}
	return 0;
}
/*tcp连接是否正常*/
ms_bool msnet_api_isTcpStateOK(ms_s32  	    fd , struct tcp_info* ptcp_info,ms_byte *pstr_tcpi_state)
{
	ms_bool ret=ms_true;
	struct tcp_info info; 
	struct tcp_info* ptcp_info_use=(ms_null!=ptcp_info) ? ptcp_info : &info;
	int tinfo_len=sizeof(struct tcp_info); 
	ms_memset0(ptcp_info_use, tinfo_len);
	if(getsockopt(fd, IPPROTO_TCP, TCP_INFO, ptcp_info_use, (socklen_t *)&tinfo_len)<0){
		if(ms_null!=pstr_tcpi_state){
			ms_strcpy(pstr_tcpi_state, "getsockopt TCP_INFO failed");
		}
		ms_error("getsockopt TCP_INFO failed");
		ret=ms_false;
	}else{
		if(ptcp_info_use->tcpi_state!=msnet_tcp_established ){
			char str_tcpi_state[256]={0};
			ms_byte * pstrstate=(ms_null!=pstr_tcpi_state) ? pstr_tcpi_state : str_tcpi_state;
			msnet_api_getTcpStateString(ptcp_info_use->tcpi_state, pstrstate);
			if(ms_null==pstr_tcpi_state){
				ms_waring("The TCP connection is abnormal %s",pstrstate);
			}
			ret=ms_false;
		}
	}
	return ret;
}
//donot use poll,may case program cash ,when call it large than 996
ms_s32 msnet_api_epollRecv(ms_s32 ms_in fd ,  ms_pu08 ms_in  pbuf, ms_u32 ms_in  size,ms_u32 ms_in  timeout)
{
	ms_bufcheckRetDes(msepoll_ret_param_error, pbuf, "Param error####pbuf");
	if(size>ms_sf(ms_f32)){
		ms_waring("Recv len(%d) is out of range(0~%d),set to %d",size,ms_sf(ms_f32),ms_sf(ms_f32));
		size=ms_sf(ms_f32);
	}
	ms_s32 ret=0;
	ms_s32 epfd=msepoll_open(2);
	ms_u64 time_base=mstime_api_us();
	 if (-1!=timeout){
		MSEPOLLRet ret_epoll=msepoll_waitfd_timeout(epfd, fd, 0, timeout);
		if (ret_epoll < 0){
			msepoll_close(&epfd);
			return ret_epoll;
		}
	}
	msepoll_close(&epfd);
	 
	ret = recv(fd, pbuf, size, 0);	
	if (ret<0){
		ms_close(fd);
		ms_errRet(msepoll_ret_io_error, "recv error(%d): %d %s\n", ret,errno, strerror(errno));
	}

	//如果epoll快速返回有数据，但又读取不到。那么有可能对端发起了关闭连接的请求,如果UDP咋办？
	if (-1!=timeout && 0==ret ){
		ms_u64 time_now=mstime_api_us();
		if(time_now < time_base ){
			ms_waring("The current time is less than the previous time, and the system time may have changed")
		}else{
			ms_u64 time_cha=time_now-time_base;
			if(time_cha<ms_usmseconds(timeout)){
				char str_tcpi_state[128]={0};
				 struct tcp_info tcp_info;
				if(ms_false==msnet_api_isTcpStateOK(fd, &tcp_info,str_tcpi_state)){
					if(tcp_info.tcpi_state!=msnet_tcp_closewait){
						ms_waring("Epoll returns data quickly, but cannot read it. The TCP connection is abnormal %s",str_tcpi_state);
					}
					ret=msepoll_ret_abnormal_connection;
				}	
			}
		}
	}
	return ret;
}
ms_s32 msnet_api_epollRecv3(ms_s32 ms_in fd ,  ms_pu08 ms_in  pbuf, ms_u32 ms_in  size) 
{
	return msnet_api_epollRecv(fd, pbuf,size, msnet_default_timeout_recv);
}
ms_s32 msnet_api_epollSend(ms_s32 ms_in fd ,  ms_pu08 ms_in  pbuf, ms_u32 ms_in  size,ms_u32 ms_in  timeout)
{
	ms_bufcheckRetDes(msepoll_ret_param_error, pbuf, "Param error####pbuf");
	if(size>ms_sf(ms_f32)){
		ms_waring("Recv len(%d) is out of range(0~%d),set to %d",size,ms_sf(ms_f32),ms_sf(ms_f32));
		size=ms_sf(ms_f32);
	}
	ms_s32 ret=0;
	ms_s32 epfd=msepoll_open(2);
	if (-1!=timeout){
		MSEPOLLRet ret_epoll=msepoll_waitfd_timeout(epfd, fd, 1, timeout);
		if (ret_epoll < 0){
			msepoll_close(&epfd);
			return ret_epoll;
		}
	}
	msepoll_close(&epfd);
	ret = send(fd, pbuf, size, 0);	
	if (ret<0){
		ms_close(fd);
		ms_errRet(msepoll_ret_io_error, "send error(%d): %d %s\n", ret,errno, strerror(errno));
	}
	return ret;
}
ms_s32 msnet_api_epollSend2(ms_s32 ms_in fd ,  ms_pu08 ms_in  pbuf, ms_u32 ms_in  size,ms_u32 ms_in  timeout) 
{
	int sendlen_old=0;
	int sendlen_cur=0;
	int datalen=size;
	int sendlen=0;
	while(0!=datalen){
		sendlen=(datalen>1400) ? 1400 : datalen;
		sendlen_cur= msnet_api_epollSend(fd ,&pbuf[sendlen_old],sendlen,timeout);
		if(0>sendlen_cur){
			ms_error("Send info data error");
			sendlen_old=sendlen_cur;
			break;
		}	
		datalen-=sendlen_cur;
		sendlen_old+=sendlen_cur;
	}
	return sendlen_old;
}
ms_s32 msnet_api_epollSend3(ms_s32 ms_in fd ,  ms_pu08 ms_in  pbuf, ms_u32 ms_in  size) 
{
	return msnet_api_epollSend2(fd, pbuf,size, msnet_default_timeout_send);
}
ms_u08 msnet_api_getNetmaskBitNum(ms_string ms_in pnetmask)
{
	ms_byte netmask[256]={0};	
	ms_strcpy(netmask, pnetmask);
	
	ms_string str_netmask_item[256];
	ms_u08  netmask_item[4]={0};
	ms_u08 netmask_num=msstr_api_split(netmask, ".", str_netmask_item);	
	if(4!=netmask_num){
		ms_errRet(ms_false, "Error netmask(%s),num is %d",netmask,netmask_num)
	}
	ms_u08 index=0;
	ms_u08 totalbit_netmask=0;
	ms_u08  netmask_out_num[4]={0};
	for(index=0;index<4;index++){
		netmask_item[index]=ms_atoi(str_netmask_item[index]);
		switch(netmask_item[index]){
			case 0x80:totalbit_netmask+=1;break;
			case 0xC0:totalbit_netmask+=2;break;
			case 0xE0:totalbit_netmask+=3;break;
			case 0xF0:totalbit_netmask+=4;break;
			case 0xF8:totalbit_netmask+=5;break;
			case 0xFC:totalbit_netmask+=6;break;
			case 0xFE:totalbit_netmask+=7;break;
			case 0xFF:totalbit_netmask+=8;break;
		}
	}
	return totalbit_netmask;
}
ms_bool msnet_api_getGatewayByNetmask(ms_string ms_in pipaddr,ms_string ms_in pnetmask,ms_string ms_out netmask_out,ms_string ms_out usr_gateway)
{
	ms_byte ipaddr[256]={0};
	ms_byte netmask[256]={0};	
	ms_strcpy(ipaddr, pipaddr);
	ms_strcpy(netmask, pnetmask);
	
	ms_string str_netmask_item[256];
	ms_u08  netmask_item[4]={0};
	ms_u08 netmask_num=msstr_api_split(netmask, ".", str_netmask_item);	
	if(4!=netmask_num){
		ms_errRet(ms_false, "Error netmask(%s),num is %d",netmask,netmask_num)
	}
	ms_string str_ipaddr_item[256];
	ms_u08  ipaddr_item[4]={0};
	ms_u08 ipaddr_num=msstr_api_split(ipaddr, ".", str_ipaddr_item);	
	if(4!=ipaddr_num){
		ms_errRet(ms_false, "Error ipaddr(%s),num is %d",ipaddr,ipaddr_num)
	}

	ms_u08 index=0;
	ms_u08 totalbit_netmask=0;
	ms_u08  netmask_out_num[4]={0};
	for(index=0;index<4;index++){
		netmask_item[index]=ms_atoi(str_netmask_item[index]);
		ipaddr_item[index]=ms_atoi(str_ipaddr_item[index]);
		
		netmask_out_num[index]=netmask_item[index]&ipaddr_item[index];
		switch(netmask_item[index]){
			case 0x80:totalbit_netmask+=1;break;
			case 0xC0:totalbit_netmask+=2;break;
			case 0xE0:totalbit_netmask+=3;break;
			case 0xF0:totalbit_netmask+=4;break;
			case 0xF8:totalbit_netmask+=5;break;
			case 0xFC:totalbit_netmask+=6;break;
			case 0xFE:totalbit_netmask+=7;break;
			case 0xFF:totalbit_netmask+=8;break;
		}
	}
	if(ms_null!=netmask_out){	
		ms_sprintfs(netmask_out,"%d.%d.%d.%d/%d",
			netmask_out_num[0],
			netmask_out_num[1],
			netmask_out_num[2],
			netmask_out_num[3],
			totalbit_netmask);
	}
	if(ms_null!=usr_gateway){
		ms_sprintfs(usr_gateway,"%d.%d.%d.%d",
			netmask_out_num[0],
			netmask_out_num[1],
			netmask_out_num[2],
			(netmask_out_num[3]+1));
	}
}
ms_bool msnet_api_subnet(ms_string ms_in pipaddr,ms_string ms_in pnetmask,ms_string ms_out netmask_out)
{
	ms_byte ipaddr[256]={0};
	ms_byte netmask[256]={0};	
	ms_strcpy(ipaddr, pipaddr);
	ms_strcpy(netmask, pnetmask);
	
	ms_string str_netmask_item[256];
	ms_u08  netmask_item[4]={0};
	ms_u08 netmask_num=msstr_api_split(netmask, ".", str_netmask_item);	
	if(4!=netmask_num){
		ms_errRet(ms_false, "Error netmask(%s),num is %d",netmask,netmask_num)
	}
	ms_string str_ipaddr_item[256];
	ms_u08  ipaddr_item[4]={0};
	ms_u08 ipaddr_num=msstr_api_split(ipaddr, ".", str_ipaddr_item);	
	if(4!=ipaddr_num){
		ms_errRet(ms_false, "Error ipaddr(%s),num is %d",ipaddr,ipaddr_num)
	}

	ms_u08 index=0;
	ms_u08  netmask_out_num[4]={0};
	for(index=0;index<4;index++){
		netmask_item[index]=ms_atoi(str_netmask_item[index]);
		ipaddr_item[index]=ms_atoi(str_ipaddr_item[index]);
		netmask_out_num[index]=netmask_item[index]&ipaddr_item[index];
	}
	if(ms_null!=netmask_out){	
		ms_sprintfs(netmask_out,"%d.%d.%d.%d",
			netmask_out_num[0],
			netmask_out_num[1],
			netmask_out_num[2],
			netmask_out_num[3]);
	}
}

ms_s32 msnet_api_getIpList(ms_string ms_in str_ipaddr_start,ms_string ms_in str_ipaddr_end,ms_string ms_out pmipaddrs,ms_u08 arrsize)
{

	ms_u32 ipaddr_start	=msnet_api_ipStr2Byte(str_ipaddr_start);
	ms_u32 ipaddr_end		=msnet_api_ipStr2Byte(str_ipaddr_end);
	ms_u32 num_ipaddr=0;
	ms_u32 index=0;
	for(index=ipaddr_start;ms_noMore(index, ipaddr_end);index++){
		ms_string pipaddr=&pmipaddrs[num_ipaddr*arrsize];
		msnet_api_ipByte2Str(index, pipaddr);
		num_ipaddr+=1;
	}
	return num_ipaddr;
}


ms_bool msnet_api_isVaildFd(ms_s32 fd)
{
	return  ms_moreThan(fd, 2) ? ms_true : ms_false;
}
NETCFG_MODE msnet_api_getIpMode(ms_u08* ms_in mode_string)
{
	ms_string ethmod[128]={ethnmode_string};
	ms_u08 index=0;
	for(index=0;index<netcfg_mode_max;index++){
		if(ms_strncmp_saeq(mode_string,ethmod[index]) !=0){
			return (NETCFG_MODE)index;
			break;
		}
	}
	return netcfg_mode_unknow;
}

ms_string msnet_api_net2str(ms_pbyte pbuf)
{
	return (ms_string)inet_ntoa( *(struct in_addr *)(pbuf));
}
ms_void msnet_api_num2str(ms_pbyte pbuf,ms_u32 len,ms_pbyte pstrout)
{
	ms_memcpy(pstrout, pbuf, len);
}
ms_void msnet_api_str2num(ms_pbyte pstrin,ms_u32 len,ms_pbyte pbuf)
{
	ms_memcpy(pbuf, pstrin, len);
}

ms_void msnet_api_num2str16(ms_pbyte pbuf,ms_u32 len,ms_pbyte pstrout)
{
	ms_u32 index=0;
	ms_u08 tbuf[16]={0};
	for(index=0;index<len;index++){
		ms_strcats(tbuf, pstrout, "%02x", pbuf[index]);
	}
}
ms_bool msnet_api_ping( ms_string ipaddr)
{
	if(ms_null==ipaddr
		||0==ms_buflen(ipaddr)){
		return ms_false;
	}
	if(ms_false==msmd_api_isInstallByBin("ping")){
		return ms_false;
	}
	ms_byte ping_cmd[128]={0};		
	ms_sprintfs(ping_cmd, "ping -c 1  -s 16  -W 2 %s ", ipaddr);
	ms_verbose("ping_cmd:%s", ping_cmd);
	return ms_cmdRet(ping_cmd);
}
#undef MSNETWORK_C

